<script>
/**
 * 搜索模块 组件
 * 必须接受的 props
 *
 * filter (要绑定的对象)
 * fileds (各表单配置)
 */
import moment from "moment";
import { focusElement } from "@/util/common.js";
export default {
  name: "HeaderSearch",
  functional: true,
  render(h, context) {
    /**
     * Render 页面生成
     */
    const items = itemsRender(h);
    return h(
      "div",
      {
        class: "page-header-search",
        style: context.data.staticStyle,
        ref: context.data.ref,
        props: context.props,
      },
      items
    );
    /**
     * 渲染 搜索组件
     */
    function itemsRender() {
      const fileds = context.props.fileds;
      const res = [];
      for (const i in fileds) {
        res.push(
          h(
            "div",
            {
              class: "search-item",
            },
            componentUse(fileds[i], i)
          )
        );
      }
      if (context.children) res.push(h("div", context.children));
      return res;
    }
    /**
     * 判断 使用什么组件
     */
    function componentUse(attrs = {}, i) {
      const type = attrs.type || "input";
      const typeMap = {
        input: inputRender,
        select: selectRender,
        "date-picker": datePickerRender,
        "date-picker-two": datePickerTwoRender,
        "input-two": inputTwoRender,
      };
      const titleDom = titleRender(attrs, i);
      const component = typeMap[type](attrs, i);
      const res = [titleDom, component];
      return res;
    }
    /**
     * 表单标题 的渲染
     */
    function titleRender(attrs, i) {
      return h("div", {
        class: "search-item-title",
        domProps: { innerHTML: attrs.title },
      });
    }
    /**
     * 表单组件的渲染方法
     */
    // el-input
    function inputRender(attrs, i) {
      let width = "200px";
      if (attrs.props && attrs.props.width) width = attrs.props.width + "px";
      else width = getInputWidth(attrs.title);
      return h("el-input", {
        style: {
          width: width,
        },
        ...elModel(i, attrs, "input"),
      });
    }
    // el-input区间
    function inputTwoRender(attrs, i) {
      const attrsMin = getInputTwoProps(attrs, "min");
      const attrsMax = getInputTwoProps(attrs, "max");
      return h(
        "div",
        {
          class: "item-two",
        },
        [inputRender(attrsMin, `${i}Min`), inputRender(attrsMax, `${i}Max`)]
      );
    }
    // el-select
    function selectRender(attrs, i) {
      const options = computedOptions(attrs);
      let width = "200px";
      if (attrs.props && attrs.props.width) width = attrs.props.width + "px";
      else width = getInputWidth(attrs.title);
      return h(
        "el-select",
        {
          style: {
            width: width,
          },
          ...elModel(i, attrs, "change"),
        },
        options.map(optionRender)
      );
    }
    // el-option
    function optionRender(attrs = {}) {
      return h(
        "el-option",
        {
          props: {
            label: attrs.label,
            value: attrs.value,
            disabled: attrs.disabled || false,
          },
        },
        attrs.render ? attrs.render(h) : []
      );
    }
    // el-date-picker
    function datePickerRender(attrs, i) {
      let width = "200px";
      if (attrs.props && attrs.props.width) width = attrs.props.width + "px";
      else width = getInputWidth(attrs.title);
      return h("el-date-picker", {
        style: {
          width: width,
        },
        ...elModel(i, attrs, "input"),
      });
    }
    // el-date-picker区间
    function datePickerTwoRender(attrs, i) {
      const attrsStart = getDatePickerTwoProps(attrs, "start");
      const attrsEnd = getDatePickerTwoProps(attrs, "end");
      return h(
        "div",
        {
          class: "item-two",
        },
        [
          datePickerRender(attrsStart, `${i}Start`),
          datePickerRender(attrsEnd, `${i}End`),
        ]
      );
    }
    /**
     * 获取计算后的options
     */
    function computedOptions(attrs) {
      const options = attrs.options;
      const {
        value = "val",
        label = "label",
        type = String,
      } = attrs.optionKey || {};
      let results = [];
      if (Array.isArray(options)) {
        results = options.map((item) => {
          return {
            value: type(item[value]),
            label: item[label],
          };
        });
      } else {
        for (const key in options) {
          results.push({
            value: type(key),
            label: options[key],
          });
        }
      }
      return results;
    }
    /**
     * element组件的双向绑定
     */
    function elModel(key, attrs = {}, type = "input") {
      // 处理自定义指令
      const directives = [];
      if (attrs.directives) {
        for (const key in attrs.directives) {
          directives.push({
            name: key,
            value: attrs.directives[key],
          });
        }
      }
      const onFun = {}; // 组件事件
      const nativeOnFun = {}; // 原生事件
      switch (attrs.type) {
        case "input":
          // 输入组件相关监听
          nativeOnFun.keyup = function (event) {
            // 回车时触发
            if (event.keyCode === 13 && context.listeners.enter)
              context.listeners.enter();
          };
          break;
        case "select":
          // 选择组件相关监听
          onFun["visible-change"] = function (event) {
            // 下拉框出现/隐藏时触发
            focusElement(event);
            findEventAndInvoke(attrs, "visible-change");
          };
          onFun["remove-tag"] = function () {
            // 多选模式下移除tag时触发
            focusElement(false);
          };
          onFun.clear = function () {
            // 清空按钮时触发
            focusElement(false);
          };
          break;
        case "date-picker":
          // 日期组件
          onFun.change = function () {
            // 选择时触发
            focusElement(false);
          };
          break;
        case "date-picker-two":
          // 日期组件
          onFun.change = function () {
            // 选择时触发
            focusElement(false);
          };
          break;
      }
      return {
        ...attrs,
        attrs: {
          ...attrs.props,
          ...attrs.attrs,
        },
        props: {
          ...attrs.props,
          value: context.props.filter[key],
        },
        // el-selct 触发原生的change事件
        // el-date-picker 触发原生的input事件
        on: {
          ...attrs.on,
          ...onFun,
          [type](e) {
            if (attrs.type === "date-picker") {
              // 日期组件的特殊处理
              if (e === null) {
                // 用于清空
                context.props.filter[key] = null;
                return;
              }
              let dateType = "yyyy-MM-DD";
              if (
                attrs.props &&
                attrs.props.valueFormat === "yyyy-MM-dd HH:mm:ss"
              )
                dateType = "yyyy-MM-DD HH:mm:ss";
              if (moment(e).format(dateType) === e)
                context.props.filter[key] = e;
            } else {
              context.props.filter[key] = e;
              findEventAndInvoke(attrs, type);
            }
          },
          click() {
            if (context.listeners.click) context.listeners.click(key);
            findEventAndInvoke(attrs, "click");
          },
        },
        // el-input 触发组件的input事件
        nativeOn: {
          ...attrs.nativeOn,
          ...nativeOnFun,
          [type](e) {
            if (attrs.type === "date-picker") {
              // 日期组件的特殊处理
              if (e === null) {
                // 用于清空
                context.props.filter[key] = null;
                return;
              }
              let dateType = "yyyy-MM-DD";
              if (
                attrs.props &&
                attrs.props.valueFormat === "yyyy-MM-dd HH:mm:ss"
              )
                dateType = "yyyy-MM-DD HH:mm:ss";
              if (moment(e.target.value).format(dateType) === e.target.value)
                context.props.filter[key] = e.target.value;
            } else context.props.filter[key] = e.target.value;
          },
          click() {
            if (context.listeners.click) context.listeners.click(key);
            findEventAndInvoke(attrs, "click");
          },
        },
        directives: directives,
      };
    }
    /** 处理日期区间的相关参数 */
    function getDatePickerTwoProps(attrs, type) {
      let defaultTime = type === "start" ? "00:00:00" : "23:59:59";
      let placeholder =
        type === "start" ? `${attrs.title}开始` : `${attrs.title}结束`;
      let pickerOptions = {};
      if (attrs.props) {
        if (attrs.props.placeholder)
          placeholder = attrs.props.placeholder + placeholder;
        if (attrs.props.pickerOptionsStart && type === "start") {
          // 开始日期限制选择
          pickerOptions = attrs.props.pickerOptionsStart;
        }
        if (attrs.props.pickerOptionsStart && type === "end") {
          // 结束日期限制选择
          pickerOptions = attrs.props.pickerOptionsEnd;
        }
        // defaultTime
        if (attrs.props.defaultTimeStart && type === "start")
          defaultTime = attrs.props.defaultTimeStart;
        if (attrs.props.defaultTimeEnd && type === "end")
          defaultTime = attrs.props.defaultTimeEnd;
      }
      const data = {
        label: attrs.title,
        title: attrs.title,
        props: {
          ...attrs.props,
          defaultTime,
          placeholder,
          pickerOptions,
        },
        directives: attrs.directives,
        type: "date-picker",
      };
      return data;
    }
    /** 处理输入区间的相关参数 */
    function getInputTwoProps(attrs, type) {
      let placeholder =
        type === "min" ? `${attrs.title}最小值` : `${attrs.title}最大值`;
      if (attrs.props && attrs.props.placeholder)
        placeholder = attrs.props.placeholder + placeholder;
      const data = {
        label: attrs.title,
        title: attrs.title,
        props: {
          ...attrs.props,
          placeholder,
        },
        directives: attrs.directives,
        type: "el-input",
      };
      return data;
    }
    /** 宽度计算方法 */
    function getInputWidth(str = "标题") {
      const len = str.length + 3; // 加上请输入三个字的长度
      return `${len * 18 + 60}px`;
    }

    function findEventAndInvoke(attrs, eventKey) {
      if (attrs.on) {
        Object.keys(attrs.on).forEach((key) => {
          if (key === eventKey) {
            attrs.on[key]();
          }
        });
      }
    }
  },
};
</script>

<style scoped>
.page-header-search {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex-wrap: wrap;
  box-sizing: border-box;
}
.search-item {
  /* height: 45px; */
  padding-top: 8px;
  margin-right: 14px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
}
.search-item-title {
  font-size: 14px;
  color: #000;
  margin-right: 14px;
}
</style>
